﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YasharEl.Infrastructure.Core.Prototype;
using YasharEl.Infrastructure.Core.ServiceModel;
using YasharEl.Infrastructure.ObjectFactory;
using YasharEl.Infrastructure.ObjectFactory.Adapters;

namespace YasharEl.Infrastructure.ProcessEngine.ServiceModel.Adapters.Maps
{
    public class ProcessToProcessDTOMap : TypeMapConfigurationBase<IProcess, ProcessDTO>
    {
        private readonly IDependencyResolver resolver;

        public ProcessToProcessDTOMap(IDependencyResolver resolver)
        {
            Contract.Requires<ArgumentNullException>(resolver != null, "resolver could not be null.");

            this.resolver = resolver;
        }

        protected override void BeforeMap(ref IProcess source)
        {
        }

        protected override void AfterMap(ref ProcessDTO target, params object[] moreSources)
        {
        }

        protected override ProcessDTO Map(IProcess source)
        {
            ProcessDTO target = new ProcessDTO();

            ITypeAdapter typeAdapter = resolver.Resolve<ITypeAdapter>();

            if (source.ClosedBy != null)
            {
                target.ClosedBy = typeAdapter.Adapt<IProcessParticipant, ProcessParticipantDTO>(source.ClosedBy);
            }
            target.ClosedDate = source.ClosedDate;
            target.CreatedBy = typeAdapter.Adapt<IProcessParticipant, ProcessParticipantDTO>(source.CreatedBy);
            target.CreatedDate = source.CreatedDate;
            RecognizeProcessStatus(target, source);
            target.ExpiredDate = source.ExpiredDate;
            if (target.ModifiedBy != null)
            {
                target.ModifiedBy = typeAdapter.Adapt<IProcessParticipant, ProcessParticipantDTO>(source.ModifiedBy);
            }
            target.ModifiedDate = source.ModifiedDate;
            target.Owner = typeAdapter.Adapt<IProcessParticipant, ProcessParticipantDTO>(source.Owner);
            RecognizeProcessPriority(target, source);
            target.StartedDate = source.StartedDate;
            target.WorkflowInstanceId = source.WorkflowInstanceId;

            target.PropertyAssignments = new PropertyAssignments();
            if (source.Properties != null && source.Properties.Count > 0)
            {
                foreach (IPropertyInstance propertyInstance in source.Properties)
                {
                    PropertyAssignmentDTO assignmentDTO = 
                        typeAdapter.Adapt<IPropertyInstance, PropertyAssignmentDTO>(propertyInstance);
                    target.PropertyAssignments.Add(assignmentDTO.PropertyDefinition.PropertyKey, assignmentDTO);
                }
            }
            
            return target;
        }

        private void RecognizeProcessPriority(ProcessDTO target, IProcess source)
        {
            target.ProcessPriority = null;

            if (source.ProcessPriority != null)
            {
                if (source.ProcessPriority == YasharEl.Infrastructure.ProcessEngine.ProcessPriority.High)
                {
                    target.ProcessPriority = new ProcessPriorityDescriptionDTO()
                    {
                        ProcessPriority = ProcessPriority.High,
                        ProcessPriorityCode = YasharEl.Infrastructure.ProcessEngine.ProcessPriority.High.Value,
                        ProcessPriorityDescription = YasharEl.Infrastructure.ProcessEngine.ProcessPriority.High.ShortName
                    };
                }
                else if (source.ProcessPriority == YasharEl.Infrastructure.ProcessEngine.ProcessPriority.Low)
                {
                    target.ProcessPriority = new ProcessPriorityDescriptionDTO()
                    {
                        ProcessPriority = ProcessPriority.Low,
                        ProcessPriorityCode = YasharEl.Infrastructure.ProcessEngine.ProcessPriority.Low.Value,
                        ProcessPriorityDescription = YasharEl.Infrastructure.ProcessEngine.ProcessPriority.Low.ShortName
                    };
                }
                else if (source.ProcessPriority == YasharEl.Infrastructure.ProcessEngine.ProcessPriority.Normal)
                {
                    target.ProcessPriority = new ProcessPriorityDescriptionDTO()
                    {
                        ProcessPriority = ProcessPriority.Normal,
                        ProcessPriorityCode = YasharEl.Infrastructure.ProcessEngine.ProcessPriority.Normal.Value,
                        ProcessPriorityDescription = YasharEl.Infrastructure.ProcessEngine.ProcessPriority.Normal.ShortName
                    };
                }
                else
                {
                    throw new ProcessPriorityEnumerationException(
                        source.ProcessPriority,
                        string.Format("ProcessPriority is not recognized : {0}.", source.ProcessPriority)
                    );
                }
            }
        }

        private void RecognizeProcessStatus(ProcessDTO target, IProcess source)
        {
            target.CurrentStatus = null;

            if (source.ProcessStatus != null)
            {
                if (source.ProcessStatus == YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Active)
                {
                    target.CurrentStatus = new ProcessStatusDescriptionDTO()
                    {
                        ProcessStatus = ProcessStatus.Active,
                        ProcessStatusCode = YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Active.Value,
                        ProcessStatusDescription = YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Active.ShortName
                    };
                }
                else if (source.ProcessStatus == YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Closed)
                {
                    target.CurrentStatus = new ProcessStatusDescriptionDTO()
                    {
                        ProcessStatus = ProcessStatus.Closed,
                        ProcessStatusCode = YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Closed.Value,
                        ProcessStatusDescription = YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Closed.ShortName
                    };
                }
                else if (source.ProcessStatus == YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Cancelled)
                {
                    target.CurrentStatus = new ProcessStatusDescriptionDTO()
                    {
                        ProcessStatus = ProcessStatus.Cancelled,
                        ProcessStatusCode = YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Cancelled.Value,
                        ProcessStatusDescription = YasharEl.Infrastructure.ProcessEngine.ProcessStatus.Cancelled.ShortName
                    };
                }
                else
                {
                    throw new ProcessStatusEnumerationException(
                        source.ProcessStatus, 
                        string.Format("ProcessStatus is not recognized : {0}.", source.ProcessStatus)
                    );
                }
            }
        }
    }
}
